package com.example.index.reflect

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.index.R
import com.example.index.util.ReflectUtil
import kotlinx.android.synthetic.main.activity_base_list.*
import java.lang.reflect.Constructor
import java.lang.reflect.ParameterizedType

abstract class BaseListActivity<T, VH : RecyclerView.ViewHolder> : AppCompatActivity() {

    val baseDatas = arrayListOf<T>()

    lateinit var baseListAdapter: BaseListAdapter

    var viewHolderConstructor: Constructor<*>? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_base_list)

        recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
        baseListAdapter = BaseListAdapter()
        recyclerView.adapter = baseListAdapter

        smartRefreshLayout.setOnLoadMoreListener {
            startLoadMore()
        }

        smartRefreshLayout.setOnRefreshListener {
            startRefresh()
        }
    }

    fun adapter() = baseListAdapter

    abstract fun startLoadMore()

    abstract fun startRefresh()

    fun onRefreshFinish() {
        baseDatas.clear()
        baseListAdapter.notifyDataSetChanged()
    }


    fun onLoadMoreData(datas: List<T>) {
        val oldList = arrayListOf<T>()
        oldList.addAll(baseDatas)
        baseDatas.addAll(datas)

        DiffUtil.calculateDiff(DiffCallBackImpl(oldList, baseDatas)).dispatchUpdatesTo(baseListAdapter)
        stopLoadMore()
    }

    fun onRefreshData(datas: List<T>) {
        val oldList = arrayListOf<T>()
        oldList.addAll(baseDatas)
        baseDatas.clear()
        baseDatas.addAll(datas)
        DiffUtil.calculateDiff(DiffCallBackImpl(oldList, baseDatas)).dispatchUpdatesTo(baseListAdapter)
        stopRefresh()
    }

    fun stopRefresh() = smartRefreshLayout.finishRefresh()


    fun stopLoadMore() = smartRefreshLayout.finishLoadMore()

    fun notifyDataSetChange() = recyclerView.adapter?.notifyDataSetChanged()

    @LayoutRes
    abstract fun getLayoutRes(): Int

    open fun onBindViewHolder(holder: VH, item: T){

     }

    open fun onBindViewHolder(holder: VH, item: T, payLoads: MutableList<Any>) {

    }

    inner class BaseListAdapter : RecyclerView.Adapter<VH>() {


        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
            return reflectCreateViewHolder(layoutInflater.inflate(getLayoutRes(), parent, false))
        }

        override fun getItemCount() = baseDatas.size

        override fun onBindViewHolder(holder: VH, position: Int) {
            onBindViewHolder(holder, baseDatas[holder.adapterPosition])
        }

        override fun onBindViewHolder(holder: VH, position: Int, payloads: MutableList<Any>) {
//            super.onBindViewHolder(holder, position, payloads)
            onBindViewHolder(holder, baseDatas[position], payloads)
        }

    }

    private fun reflectCreateViewHolder(inflate: View?): VH {

        if (viewHolderConstructor == null) {
            val type = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[1]
            viewHolderConstructor = ReflectUtil.getRawType(type).constructors[0]
        }

        return viewHolderConstructor?.newInstance(inflate) as VH
    }


    class DiffCallBackImpl<T>(var oldList: List<T>, var newList: List<T>) : DiffUtil.Callback() {

        override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) =
            oldList[oldItemPosition]?.equals(newList[newItemPosition]) ?: false

        override fun getOldListSize() = oldList.size

        override fun getNewListSize() = newList.size

        override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) =
            oldList[oldItemPosition]?.equals(newList[newItemPosition]) ?: false

    }
}
